package presentation;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;

@SuppressWarnings("serial")
public class ApfelMannPanel extends JPanel {

	private BufferedImage img;

	private static double cMinX = -2;
	private static double cMaxX = 1;
	private static double cMinY = -1.5;
	private static double cMaxY = 1.5;

	private int maxIterrationen = 1200;

	private Double pixelAnz;

	private SelectionBox selectionBox;

	private boolean isZoomMode;

	// TEST-VARS (to delete)
	// =====================

	private double test;

	public ApfelMannPanel() {
		this.isZoomMode = false;
		this.setPreferredSize(new Dimension(800, 800));
	}

	@Override
	public void paint(Graphics g) {

		super.paint(g);

		Graphics2D graphics = (Graphics2D) g;

		graphics.drawImage(img, 0, 0, this);

		if (isZoomMode) {
			selectionBox.draw(graphics);
		}

	}

	public void generateImage() {

		pixelAnz = (double) (getWidth() * getHeight());
		int currentPixel = 0;

		int w = getWidth(), h = getHeight();
		img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
		double a, b;

		for (int i = 0; i < h; i++) {
			b = (double) i * (cMaxY - cMinY) / h + cMinY;
			for (int j = 0; j < w; j++) {
				a = (double) j * (cMaxX - cMinX) / w + cMinX;
				int iterationen = getElement(a, b);

				img.setRGB(j, i, getColor(iterationen).getRGB());

				int lastPixel = currentPixel;
				currentPixel++;

				firePropertyChange("Fortschritt", lastPixel/pixelAnz, currentPixel/pixelAnz);
			}
		}

		if (maxIterrationen < 25000)
			maxIterrationen *= 1.2d;
		repaint();
	}

	private Color getColor(int iterationen) {

		// if (iterationen == maxIterrationen) {
		// return Color.BLACK;
		// } else if (iterationen >= (maxIterrationen / 2d)
		// && iterationen < maxIterrationen) {
		// return Color.BLUE;
		// } else if (iterationen >= (maxIterrationen / 4d)
		// && iterationen < (maxIterrationen / 2d)) {
		// return Color.CYAN;
		// } else if (iterationen >= (maxIterrationen / 8d)
		// && iterationen < (maxIterrationen / 4d)) {
		// return Color.MAGENTA;
		// } else if (iterationen >= (maxIterrationen / 16d)
		// && iterationen < (maxIterrationen / 8d)) {
		// return Color.RED;
		// } else if (iterationen >= (maxIterrationen / 32d)
		// && iterationen < (maxIterrationen / 16d)) {
		// return Color.ORANGE;
		// } else if (iterationen >= (maxIterrationen / 64d)
		// && iterationen < (maxIterrationen / 32d)) {
		// return Color.YELLOW;
		// }
		//
		// return Color.WHITE;

		float r;
		float g;
		float b;

		double colorValue;

		if (iterationen == maxIterrationen) {
			return Color.BLACK;
		}

		colorValue = ((float) iterationen - ((Math.log(Math.log(Math
				.sqrt(this.test)))) / Math.log(2.0))) / (float) maxIterrationen;

		// 10 16 50
		r = (float) Math.sin(colorValue * 10);
		g = (float) Math.sin(colorValue * 16);
		b = (float) Math.sin(colorValue * 50);

		if (r < 0) {
			r *= -1;
		}

		if (g < 0) {
			g *= -1;
		}

		if (b < 0) {
			b *= -1;
		}

		// System.out.println(r + " || " + g + " || "+ b);

		Color color = new Color(r, g, b);

		return color;
	}

	/**
	 * Bestimmt, ob ein Punkt in der Mandelbrotmenge liegt und gibt die Anzahl
	 * der Berechnugsschritte zur Bestimmung dieses Faktes zur�ck.
	 * 
	 * @param a
	 * @param b
	 * @return
	 */
	private int getElement(double a, double b) {
		double x = 0, x2, y = 0;
		int n;
		for (n = 0; n < maxIterrationen; n++) {
			x2 = x * x - y * y + a;
			y = 2 * x * y + b;
			x = x2;
			if (x * x + y * y > 4) {
				this.test = x * x + y * y;
				return n;
			}
		}
		return n;
	}

	public void setNewBounds(int newXMin, int newXMax, int newYMin, int newYMax) {

		double cRangeX = cMaxX - cMinX;
		double cRangeY = cMaxY - cMinY;

		double verschiebungInPositveXRichtung = (cRangeX * newXMin)
				/ getWidth();
		cMinX += verschiebungInPositveXRichtung;

		double verschiebungInNegativeXRichtung = (cRangeX * (getWidth() - newXMax))
				/ getWidth();
		cMaxX -= verschiebungInNegativeXRichtung;

		double verschiebungInPositveYRichtung = (cRangeY * newYMin)
				/ getHeight();
		cMinY += verschiebungInPositveYRichtung;

		double verschiebungInNegativeYRichtung = (cRangeY * (getHeight() - newYMax))
				/ getHeight();
		cMaxY -= verschiebungInNegativeYRichtung;
	}

	public void setSelectionBox(SelectionBox selectionBox) {
		this.selectionBox = selectionBox;
	}

	public void setZoomMode(boolean isZoomMode) {
		this.isZoomMode = isZoomMode;
	}
}